package 正则表达式;
/*
public class 捕获组命名 {

}

Java 正则表达式的捕获组(capture group)

捕获组分为：
--普通捕获组(Expression)
--命名捕获组(?Expression)

《普通捕获组》
从正则表达式左侧开始，每出现一个左括号"("记做一个分组，分组编号从 1 开始。0 代表整个表达式。

对于时间字符串：2017-04-25，表达式如下

(\\d{4})-((\\d{2})-(\\d{2}))
有 4 个左括号，所以有 4 个分组:

编号 捕获组                        匹配
0	(\d{4})-((\d{2})-(\d{2}))	2017-04-25
1	(\d{4})	                    2017
2	((\d{2})-(\d{2}))	        04-25
3	(\d{2})	                    04
4	(\d{2})	                    25

public static final String DATE_STRING = "2017-04-25";
public static final String P_COMM = "(\\d{4})-((\\d{2})-(\\d{2}))";
 
Pattern pattern = Pattern.compile(P_COMM);
Matcher matcher = pattern.matcher(DATE_STRING);
matcher.find();//必须要有这句
System.out.printf("\nmatcher.group(0) value:%s", matcher.group(0));
System.out.printf("\nmatcher.group(1) value:%s", matcher.group(1));
System.out.printf("\nmatcher.group(2) value:%s", matcher.group(2));
System.out.printf("\nmatcher.group(3) value:%s", matcher.group(3));
System.out.printf("\nmatcher.group(4) value:%s", matcher.group(4));

《命名捕获组》
每个以左括号开始的捕获组，都紧跟着 ?，而后才是正则表达式。

对于时间字符串：2017-04-25，表达式如下:
(?<year>\\d{4})-(?<md>(?<month>\\d{2})-(?<date>\\d{2}))

有 4 个命名的捕获组，分别是:

编号 名称      捕获组                            匹配
0	0	     (?\d{4})-(?(?\d{2})-(?\d{2}))   2017-04-25
1	year	 (?\d{4})-                       2017
2	md	     (?(?\d{2})-(?\d{2}))            04-25
3	month	 (?\d{2})                        04
4	date	 (?\d{2})                        25

命名的捕获组同样也可以使用编号获取相应值。

public static final String P_NAMED = "(?<year>\\d{4})-(?<md>(?<month>\\d{2})-(?<date>\\d{2}))";
public static final String DATE_STRING = "2017-04-25";
 
Pattern pattern = Pattern.compile(P_NAMED);
Matcher matcher = pattern.matcher(DATE_STRING);
matcher.find();
System.out.printf("\n===========使用名称获取=============");
System.out.printf("\nmatcher.group(0) value:%s", matcher.group(0));
System.out.printf("\n matcher.group('year') value:%s", matcher.group("year"));
System.out.printf("\nmatcher.group('md') value:%s", matcher.group("md"));
System.out.printf("\nmatcher.group('month') value:%s", matcher.group("month"));
System.out.printf("\nmatcher.group('date') value:%s", matcher.group("date"));
matcher.reset();
System.out.printf("\n===========使用编号获取=============");
matcher.find();
System.out.printf("\nmatcher.group(0) value:%s", matcher.group(0));
System.out.printf("\nmatcher.group(1) value:%s", matcher.group(1));
System.out.printf("\nmatcher.group(2) value:%s", matcher.group(2));
System.out.printf("\nmatcher.group(3) value:%s", matcher.group(3));
System.out.printf("\nmatcher.group(4) value:%s", matcher.group(4));

《PS:非捕获组》
在左括号后紧跟 ?:，而后再加上正则表达式，构成非捕获组 (?:Expression)。

对于时间字符串：2017-04-25，表达式如下:
(?:\\d{4})-((\\d{2})-(\\d{2}))
这个正则表达式虽然有四个左括号，理论上有 4 个捕获组。但是第一组 (?:\d{4})，其实是被忽略的。当使用 matcher.group(4) 时，系统会报错。

编号	捕获组                        匹配
0	(\d{4})-((\d{2})-(\d{2}))	2017-04-25
1	((\d{2})-(\d{2}))           04-25
2	(\d{2})                     04
3	(\d{2})                     25

public static final String P_UNCAP = "(?:\\d{4})-((\\d{2})-(\\d{2}))";
public static final String DATE_STRING = "2017-04-25";
 
Pattern pattern = Pattern.compile(P_UNCAP);
Matcher matcher = pattern.matcher(DATE_STRING);
matcher.find();
System.out.printf("\nmatcher.group(0) value:%s", matcher.group(0));
System.out.printf("\nmatcher.group(1) value:%s", matcher.group(1));
System.out.printf("\nmatcher.group(2) value:%s", matcher.group(2));
System.out.printf("\nmatcher.group(3) value:%s", matcher.group(3));
 
// Exception in thread "main" java.lang.IndexOutOfBoundsException: No group 4
System.out.printf("\nmatcher.group(4) value:%s", matcher.group(4));
总结
普通捕获组使用方便；
命名捕获组使用清晰；
非捕获组目前在项目中还没有用武之地。
*/

//1. 捕获组及其编号：
//
//1) 捕获组之前讲过，就是匹配到的内容，按照()子表达式划分成若干组；
//2) 例如正则表达式：(ab)(cd(ef))就有三个捕获组，没出现一对()就是一个捕获组
//3) 捕获组编号规则：
//     i. 引擎会对捕获组进行编号，编号规则是左括号(从左到右出现的顺序，从1开始编号；
//     ii. 例如：
//     (\d{4})-(\d{2}-(\d\d))其中：  \d{4}：1组    \d{2}-(\d\d):2组   \d\d:3组
//
//2. 反向引用：
//
//1) 捕获组的作用就是为了可以在正则表达式内部或者外部（Java方法）引用它；
//2) 如何引用？当然是通过前面讲的用捕获组的编号来引用咯！
//3) 正则表达式内部引用：
//     i. \X：X是一个十进制数，X的范围必须落在捕获组编号范围之内，该表达式就匹配X号捕获组所匹配到的内容；
//     ii. 从上面的描述可以看出，\X匹配的内容是必须X号捕获组匹配成功之后才能确定的！
//     iii. 例如：([ab])\1，匹配aabbcc的结果是aa和bb，\1的内容必须要让1号捕获组捕获后才能确定，如果1号捕获的是a那么\1就是a，1号捕获到了b那么\1就是b；
//4) 正则表达式外部引用：就是用Matcher对象的start、end、group查询匹配信息时，使用捕获组编号对捕获组引用（int group）；
//
//3. 捕获组命名：
//
//1) 如果捕获组的数量非常多，那都用数字进行编号并引用将会非常混乱，并且难以记忆每个捕获组的内容及意义，因此对捕获组命名显得尤为重要；
//2) Java 7开始提供了对捕获组命名的语法，并且可以通过捕获组的名称对捕获组反向引用（内外都行）；
//     i. 命名捕获组的语法格式：(?<自定义名>expr)
//     ii. 例如：(?<year>\d{4})-(?<date>\d{2}-(?<day>\d{2}))
//         a. 有三个命名捕获组year、date和day
//         b. 从左到右编号分别为1、2、3（编号同样是有效的）
//3) 命名捕获组的反向引用：
//    i. 正则表达式内引用：\k<捕获组名称> ！例如：(?<year>\d{4})-\k<year>可以匹配1999-1999
//    ii. 外部引用：Matcher对象的start、end、group的String name参数指定要查询的捕获组的名称；
//
//4. 普通捕获组和命名捕获组的混合编号：
//
//1) 普通捕获组是相对命名捕获组的，即没有显式命名的捕获组；
//2) 当所有捕获组都是命名捕获组时那么编号规则和原来相同，即按照左括号(的出现顺序来编号；
//3) 当普通捕获组和命名捕获组同时出现时，编号规则为：先不忽略命名捕获组，只对普通捕获组按照左括号顺序编号，然后再对命名捕获组从左往右累计编号，例如：
//(\d{4})-(?<date>\d{2}-(\d\d))
//！先忽略命名命名捕获组<date>，先对普通捕获组编号\d{4}是1，\d\d是2，然后再接着累加地对命名捕获组编号，因此<date>是3；
